package com.edyd.customer.api.interceptor;

import com.edyd.customer.api.context.ActionContext;
import com.edyd.customer.api.domain.Client;
import com.edyd.customer.api.service.ClientService;
import com.fow.core.platform.crypto.HMAC;
import com.fow.core.platform.exception.ForbiddenException;
import com.fow.core.platform.exception.UserAuthorizationException;
import com.fow.core.platform.http.HTTPHeaders;
import com.fow.core.platform.web.filter.RequestWrapper;
import com.fow.core.util.Convert;
import com.fow.core.util.EncodingUtils;
import com.fow.core.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.Charset;


/**
 * Created by Administrator on 14-10-18.
 */
@Order(0)
public class ClientAuthInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private ClientService clientService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        authenticateClient((RequestWrapper) request);

        return true;
    }

    private void authenticateClient(RequestWrapper request) throws Exception {

        String clientId = request.getHeader(HTTPHeaders.HEADER_CLIENT_ID);
        if (!StringUtils.hasText(clientId))
            throw new ForbiddenException("client-id header is required");

        String signature = request.getHeader(HTTPHeaders.HEADER_CLIENT_SIGNATURE);
        if (!StringUtils.hasText(signature))
            throw new ForbiddenException("client-signature header is required");

        String requestId = request.getHeader(HTTPHeaders.HEADER_REQUEST_ID);
        if (!StringUtils.hasText(requestId))
            throw new ForbiddenException("request-id header is required");

        Client client = clientService.selectById(clientId);

        if(client == null)
            throw new ForbiddenException("client-id is invalid");

        isExpired(request);

        String message = buildSignedMessage(request);
        String exceptedSignature =  EncodingUtils.encryptBASE64(HMAC.encryptHMAC(message.getBytes(Charset.forName("UTF-8")), client.getSecretKey()));
        //验证签名

        if(!signature.equalsIgnoreCase(exceptedSignature))
            throw new ForbiddenException("client-signature header is invalid");

        request.setAttribute(ActionContext.CURRENT_CLIENT,client);

    }

    /**
     * 原始签名
     * @param request
     * @return
     */
    private String buildSignedMessage(RequestWrapper request) {
        String timestamp = request.getHeader(HTTPHeaders.HEADER_TIMESTAMP);

        StringBuilder builder = new StringBuilder(300);
        builder.append("uri=").append(request.getRequestURI());
        builder.append("&method=").append(request.getMethod().toUpperCase());
        if(StringUtils.hasText(request.getBody()))
            builder.append("&body=").append(request.getBody());
        builder.append("&timestamp=").append(timestamp);

        return builder.toString();
    }

    private void isExpired(RequestWrapper request) {
        String timestamp = request.getHeader(HTTPHeaders.HEADER_TIMESTAMP);

        if (!StringUtils.hasText(timestamp))
            throw new UserAuthorizationException("timestamp header is required");

        Long clientTimestamp = Convert.toLong(timestamp, null);
        if (clientTimestamp == null) {
            throw new UserAuthorizationException("timestamp header is invalid");
        }
        Long serverTimeStamp = System.currentTimeMillis();
        if(clientTimestamp + (300 * 1000) < serverTimeStamp){
            throw new UserAuthorizationException(String.format("request expired, clientTime=%s, serverTime=%s", clientTimestamp,serverTimeStamp));
        }
    }

}